//
// ResultSet.h
//
// ResultSet imp.
//
// Copyright (c) 2009, Renato Tegon Forti - re.tf@acm.org
//
// 
// THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
// IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
// FITNESS FOR A PARTICULAR PURPOSE, TITLE AND NON-INFRINGEMENT. IN NO EVENT
// SHALL THE COPYRIGHT HOLDERS OR ANYONE DISTRIBUTING THE SOFTWARE BE LIABLE
// FOR ANY DAMAGES OR OTHER LIABILITY, WHETHER IN CONTRACT, TORT OR OTHERWISE,
// ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER
// DEALINGS IN THE SOFTWARE.
//

#pragma once
#include <iostream>
#include <string>
#include <vector>
#include <map>

namespace Arrow_DB_Assistant
{



typedef std::map<std::string,size_t> FieldIndex;
typedef std::vector<std::string> RowData;

class ResultRow
	{
		friend class ResultTable;
	public:
		ResultRow(){};
		~ResultRow(){};

		ResultRow& operator = (const ResultRow& t)
		{
			_fieldIndex = t._fieldIndex;
			_rowData = t._rowData;
			return *this;
		}


		int countFields()
		{
			return _rowData.size();
		}

		bool getField(int nIndex, std::string& strValue)
		{
			if (nIndex < 0 || nIndex > _rowData.size())
			{
				return false;
			}
			strValue = _rowData[nIndex];
			return true;
		}

		bool setField(std::string strFieldName, std::string& strValue)
		{
			FieldIndex::iterator it = _fieldIndex.find(strFieldName);
			if (it == _fieldIndex.end())
			{
				return false;
			}
			_rowData[it->second] = strValue;
			return true;
		}

		bool setField(int nIndex, std::string& strValue)
		{
			if (nIndex < 0 || nIndex > _rowData.size())
			{
				return false;
			}
			_rowData[nIndex] = strValue;
			return true;
		}

		bool getField(std::string strFieldName, std::string& strValue)
		{
			FieldIndex::iterator it = _fieldIndex.find(strFieldName);
			if (it == _fieldIndex.end())
			{
				return false;
			}
			strValue = _rowData[it->second];
			return true;
		}

		std::string& operator [](int nIndex)
		{
			return _rowData[nIndex];
		}

		std::string& operator[](std::string strFieldName)
		{
			return _rowData[_fieldIndex[strFieldName]];
		}
	
		bool IsEmty()
		{
			return _fieldIndex.size() == 0 || _rowData.size() == 0;
		}
	private:
		void setFieldInfo(const FieldIndex& fieldInfo)
		{
			_fieldIndex = fieldInfo;
			_rowData.resize(_fieldIndex.size());
		}
	private:
		FieldIndex _fieldIndex;
		RowData _rowData;
	};

class ResultTable
	{
		typedef std::vector<ResultRow*> TableData;
	public:

		ResultTable(): _current(0)
		{
		}

		~ResultTable()
		{
			clear();
		}


		ResultRow* newRow()
		{
			ResultRow* pTmpRow = new ResultRow();
			pTmpRow->setFieldInfo(_fieldIndex);
			return pTmpRow;
		}
		void addRow(ResultRow* pRowData)
		{
			_resultSet.push_back(pRowData);
		}

		bool fetch(size_t field, std::string& fieldValue)
		{
			size_t sz = _resultSet.size();

			if(sz)
			{
				if(sz > _current)
				{
					fieldValue = (*_resultSet[_current++])[field];

					return true;
				}
			}

			_current = 0;

			return false;
		}

		bool fetch(ResultRow*& rowValue)
		{
			size_t sz = _resultSet.size();

			if(sz)
			{
				if(sz > _current)
				{
					rowValue = _resultSet[_current++];

					return true;
				}
			}

			_current = 0;

			return false;
		}

		std::string get(size_t row, size_t field)
		{
			return (*_resultSet[row])[field];
		}

		std::string get(size_t row, std::string field)
		{
			return ((*_resultSet[row])[field]);
		}

		ResultRow& get(size_t row)
		{
			return (*_resultSet[row]);
		}

		ResultRow& operator [](size_t row)
		{
			return (*_resultSet[row]);
		}

		size_t countRows(void)
		{
			if (_resultSet.empty()) return 0;

			return _resultSet.size();
		}

		size_t countFields(void)
		{
			return _fieldIndex.size();
		}

	public:
		void setFieldInfo(const FieldIndex& fieldInfo)
		{
			_fieldIndex = fieldInfo;
		}

		void clear()
		{
			clearData();
			_fieldIndex.clear();
		}

		void clearData()
		{
			_current = 0;
			TableData::iterator it = _resultSet.begin();
			for (; it != _resultSet.end(); ++it)
			{
				delete (*it);
			}
			_resultSet.clear();
		}
	private:
		FieldIndex _fieldIndex;
		TableData _resultSet;
		size_t _current;

	}; // ResultSet
}